#include "app_task.h"         // 自定义头文件，可能包含 Task 相关定义
#include <fcntl.h>             // 用于文件控制选项，如 O_RDWR, O_CREAT
#include <mqueue.h>            // POSIX 消息队列相关函数和数据结构
#include <pthread.h>           // POSIX 线程库
#include <stddef.h>            // 一些标准定义如 NULL, size_t
#include <stdlib.h>            // 标准库，如 malloc, free, exit
#include <string.h>            // 如 memset
#include <sys/types.h>         // 系统类型定义
#include "thirdparty/log.h"    // 第三方日志库，用于记录日志（如 log_info, log_error...）

// 定义每条消息的长度：等于结构体 TaskStruct 的大小
#define MSG_LEN sizeof(struct TaskStruct)

// 定义任务结构体：包含一个任务函数指针和对应的参数
struct TaskStruct
{
    Task task;   // 任务函数指针，类型应该是 typedef void (*Task)(void *);
    void *argv;  // 传给任务的参数
};

// 全局变量
static pthread_t *executors_ptr;  // 指向所有执行器线程ID的指针
static int executors_count;       // 执行器（线程）的数量
static mqd_t mq;                  // POSIX 消息队列的描述符

// ============================
// 执行器线程函数
// 每个执行器线程不断从消息队列中接收任务并执行
// ============================
static void *app_task_executor(void *argv)
{
    int *count = (int *)argv;  // 获取当前是第几个执行器（仅用于打印日志）
    log_info("Executor %d start!", *count);  // 打印日志：执行器启动

    struct TaskStruct task_struct;

    while (1)  // 无限循环，持续监听并处理任务
    {
        // 从消息队列中接收一条消息
        // mq_receive 参数说明：
        //   - mq: 消息队列描述符
        //   - msg_ptr: 存放接收到消息的缓冲区
        //   - msg_len: 缓冲区大小
        //   - msg_prio: 接收消息的优先级（这里设为0，不关心优先级）
        if((mq_receive(mq, (char*)&task_struct, MSG_LEN, 0)) < 0)
        {
            // 如果接收失败（比如队列暂时为空），继续循环尝试
            continue;
        }

        // 调用任务函数，并传入参数
        task_struct.task(task_struct.argv);
    }

    return NULL;  // 理论上不会执行到这里
}

// ============================
// 初始化任务管理器
// 创建消息队列 + 启动多个执行器线程
// ============================
int app_task_init(int executors)
{
    // 1. 首先开启（创建或打开）消息队列
    struct mq_attr attr;
    attr.mq_maxmsg = 10;        // 消息队列中最多容纳 10 条消息
    attr.mq_msgsize  = MSG_LEN; // 每条消息的最大大小为 MSG_LEN 字节
    attr.mq_flags = 0;          // 通常为0，表示非阻塞等高级特性暂不使用
    attr.mq_curmsgs = 0;        // 当前队列中的消息数（初始化为0，一般无需设置）

    // 打开（或创建）一个 POSIX 消息队列
    // 参数说明：
    //   - "/gateway-mqueue"：消息队列的名称，必须以 / 开头且唯一
    //   - O_RDWR | O_CREAT：以读写方式打开，如果不存在则创建
    //   - 0644：权限，类似文件权限，用户可读写，其他人只读
    //   - &attr：指定队列属性
    mq = mq_open("/gateway-mqueue", O_RDWR | O_CREAT, 0644, &attr);

    if(mq < 0)  // 打开失败
    {
        log_error("mq_open error");  // 记录错误日志
        goto EXIT;                   // 跳转到退出处理
    }

    // 2. 启动后台执行器线程

    executors_count = executors;  // 保存执行器数量

    // 为执行器线程ID数组分配内存
    executors_ptr = malloc(executors_count * sizeof(pthread_t));
    if(!executors_ptr)  // 内存分配失败
    {
        log_error("Not enough memory for task manager");
        goto MQ_EXIT;  // 跳转到关闭消息队列的流程
    }

    // 将内存清零
    memset(executors_ptr, 0, executors_count * sizeof(pthread_t));

    // 循环创建多个执行器线程
    for(int i = 0; i < executors_count; i++)  // ⚠️ 注意：原代码是 i <= executors_count，会导致越界！
    {
        // 创建线程，执行 app_task_executor 函数，传入当前线程索引 i 的地址
        if(pthread_create(executors_ptr + i, NULL, app_task_executor, &i) < 0)
        {
            log_error("Failed to create executor thread %d", i);
            goto FREE_EXIT;  // 创建失败则进行资源清理
        }
    }

    log_info("Task manager started");  // 日志：任务管理器启动成功
    return 0;  // 成功返回

// ==== 错误处理分支 ====

// FREE_EXIT: 已经创建了部分线程，需要取消并回收
FREE_EXIT:
    for (int i = 0; i < executors_count; i++) 
    {
        if(executors_ptr[i])
        {
            pthread_cancel(executors_ptr[i]);      // 取消线程
            pthread_join(executors_ptr[i], NULL);  // 等待线程结束
        }
    }
    free(executors_ptr);  // 释放线程ID数组内存
    executors_ptr = NULL;

MQ_EXIT:
    mq_unlink("/gateway-mqueue");  // 删除消息队列（注意：原代码写的是 "/gateway-queue" 错误！）
    mq = (mqd_t)-1;                // 标记 mq 无效

EXIT:
    return -1;  // 失败返回 -1
}

// ============================
// 注册一个新任务到消息队列中
// ============================
int app_task_register(Task task, void *args)
{
    struct TaskStruct task_struct = {
        .task = task,  // 设置任务函数
        .argv = args   // 设置任务参数
    };

    // 将任务结构体发送到消息队列
    int result = mq_send(mq, (char *)&task_struct, MSG_LEN, 0);
    log_debug("Task %p registered", task);  // 打印调试日志，记录注册的任务函数指针
    return result;  // 返回 mq_send 的结果，成功为 0，失败为 -1
}

// ============================
// 等待所有执行器线程结束，并清理资源
// （一般用于程序正常退出前调用）
// ============================
int app_task_wait(void)
{
    log_info("Closing task manager ....");  // 日志：正在关闭任务管理器

    // 等待所有执行器线程结束
    for (int i = 0; i < executors_count; i++) 
    {
        if(executors_ptr[i])
        {
            pthread_join(executors_ptr[i], NULL);  // 阻塞等待线程i结束
        }
    }

    // 释放线程数组内存
    free(executors_ptr);
    executors_ptr = NULL;

    // 删除（unlink）消息队列，确保它被彻底移除
    mq_unlink("/gateway-mqueue"); 

    log_info("Task manager closed");  // 日志：任务管理器已关闭
    return 0;
}

// ============================
// 强制关闭所有执行器线程（不等待，直接取消）
// （可用于异常或紧急退出场景）
// ============================
void app_task_close(void)
{
    for (int i = 0; i < executors_count; i++) 
    {
        if(executors_ptr[i])
        {
            pthread_cancel(executors_ptr[i]);  // 强制取消线程
            // 注意：这里没有调用 pthread_join，意味着线程资源可能不会立即回收
        }
    }
}